﻿
namespace ThreeByte.ActiveDeck.Web.Services
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Data;
    using System.Linq;
    using System.ServiceModel.DomainServices.EntityFramework;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;
    using ThreeByte.ActiveDeck.Web.Models;
    using System.Web;
    using ThreeByte.ActiveDeck.Web.Data;
    using System.IO;
    using System.Xml.Linq;


    // Implements application logic using the ActiveDeckEntities context.
    [RequiresAuthentication]
    [EnableClientAccess(RequiresSecureEndpoint = true)]
    public class DashboardDataService : LinqToEntitiesDomainService<ActiveDeckEntities>
    {

        public IQueryable<Presentation> GetMyPresentations() {
            string username = HttpContext.Current.User.Identity.Name;

            var presentations = from pres in this.ObjectContext.Presentations
                                from p in pres.Presenters
                                where p.UserName == username
                                orderby pres.ID
                                select pres;

            return presentations;
        }

        [Update]
        public void UpdatePresentationConfig(PresentationConfig config) {
            this.ObjectContext.PresentationConfigs.AttachAsModified(config);
        }

        public Presentation GetPresentation(string presentationId) {

            return (from pres in this.ObjectContext.Presentations
                    where pres.ID == presentationId
                    select pres).Single();
        }

        public PresentationConfig GetPresentationConfig(string presentationId) {

            //Determine the last version
            int v = (from pres in this.ObjectContext.PresentationConfigs
                     where pres.PresentationID == presentationId
                     orderby pres.Version descending
                     select pres.Version).First();

            return GetPresentationConfigVersion(presentationId, v);
        }

        public PresentationConfig GetPresentationConfigVersion(string presentationId, int version) {
            return (from pres in this.ObjectContext.PresentationConfigs
                    where pres.PresentationID == presentationId
                    && pres.Version == version
                    select pres).Single();
        }

        public PresentationState GetPresentationState(string presentationId) {

            PresentationState state = (from pres in this.ObjectContext.PresentationStates
                                       where pres.PresentationID == presentationId
                                       select pres).SingleOrDefault();
            return state;
        }

        [Invoke]
        public byte[] GetResource(string presentationId, Guid resId) {

            string contentType;
            Stream resStream = CloudStorageUtil.GetResource(presentationId, resId.ToString(), out contentType);
            
            int BUFFER_SIZE = 4096;
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead = resStream.Read(buffer, 0, BUFFER_SIZE);
            using(MemoryStream memStream = new MemoryStream()) {
                while(bytesRead > 0) {
                    memStream.Write(buffer, 0, bytesRead);
                    bytesRead = resStream.Read(buffer, 0, BUFFER_SIZE);
                }
                resStream.Close();
                return memStream.GetBuffer();
            }
        }

        public IList<ResourceInfo> GetResourceInfos(string presentationId) {
            XNamespace ns = ThreeByte.ActiveDeck.Service.ServiceConfiguration.NAMESPACE;

            PresentationConfig config = GetPresentationConfig(presentationId);

            XElement el = XElement.Parse(config.XML);
            XElement resElement = el.Element(ns + "Resources");

            List<ResourceInfo> resourceList = new List<ResourceInfo>();

            foreach(XElement res in resElement.Elements(ns + "Resource")) {
                ResourceInfo newResInfo = new ResourceInfo() {
                    ID = Guid.Parse(res.Attribute("ID").Value),
                    Size = int.Parse(res.Attribute("Size").Value),
                    Type = res.Attribute("Type").Value
                };
                resourceList.Add(newResInfo);
            }
            return resourceList;
        }

        public void DeletePresentation(Presentation presentation) {
            if((presentation.EntityState != EntityState.Detached)) {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(presentation, EntityState.Deleted);
            } else {
                this.ObjectContext.Presentations.Attach(presentation);
                this.ObjectContext.Presentations.DeleteObject(presentation);
            }
        }


        public IQueryable<Presenter> GetPresenters() {
            return this.ObjectContext.Presenters;
        }

        public IQueryable<Participant> GetMyParticipants() {
            string username = HttpContext.Current.User.Identity.Name;

            var participants =  from pres in this.ObjectContext.Presentations
                                from p in pres.Presenters
                                from part in pres.Participants
                                where p.UserName == username
                                orderby pres.ID, part.UserName
                                select part;

            return participants;
        }

        public IQueryable<Participant> GetPresentationParticipants(string presentationId) {

            var participants = from pres in this.ObjectContext.Presentations
                               from part in pres.Participants
                               where pres.ID == presentationId
                               orderby part.Version descending
                               group part by part.UserName into p
                               orderby p.Key
                               select p.FirstOrDefault();

            return participants;
        }

        public IQueryable<ApprovedUser> GetMyApprovedUsers() {
            string username = HttpContext.Current.User.Identity.Name;

            var approvedUsers = from pres in this.ObjectContext.Presentations
                               from p in pres.Presenters
                               from a in pres.ApprovedUsers
                               where p.UserName == username
                               orderby pres.ID, a.UserName
                               select a;

            return approvedUsers;
        }

        public IQueryable<ApprovedUser> GetApprovedUsers(string presentationId) {
            
            var approvedUsers = from pres in this.ObjectContext.Presentations
                                from a in pres.ApprovedUsers
                                where pres.ID == presentationId
                                orderby a.UserName
                                select a;

            return approvedUsers;
        }

        public IQueryable<PresentationParticipant> GetMyParticipantSummaries() {
            string username = HttpContext.Current.User.Identity.Name;

            var participants = from pp in this.ObjectContext.PresentationParticipants
                               from p in this.ObjectContext.Presenters
                               where p.UserName == username && p.PresentationID == pp.PresentationID
                               orderby pp.PresentationID
                               select pp;

            return participants;
        }

        public void UpdateApprovedUser(ApprovedUser currentApprovedUser) {
            this.ObjectContext.ApprovedUsers.AttachAsModified(currentApprovedUser, this.ChangeSet.GetOriginal(currentApprovedUser));
        }

        public void InsertApprovedUser(ApprovedUser approvedUser) {
            if((approvedUser.EntityState != EntityState.Detached)) {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(approvedUser, EntityState.Added);
            } else {
                this.ObjectContext.ApprovedUsers.AddObject(approvedUser);
            }
        }

        public IQueryable<AddInDownload> GetAddInDownloads() {

            var downloads = from d in this.ObjectContext.AddInDownloads
                               orderby d.Timestamp descending
                               select d;
            return downloads;
        }

        public IQueryable<ErrorReport> GetErrorReports() {

            var reports = from e in this.ObjectContext.ErrorReports
                            orderby e.Timestamp descending
                            select e;
            return reports;
        }

        public string GetErrorReport(Guid id) {

            string report = null;

            //Retrieve from the Cloud service
            using(StreamReader sr = new StreamReader(CloudStorageUtil.GetErrorReport(id.ToString()))){
                report = sr.ReadToEnd();
            }

            return report;
        }

    }


    public sealed class ResourceInfo
    {
        [Key]
        public Guid ID { get; set; }
        public int Size { get; set; }
        public string Type { get; set; }
    }
}


